package com.fulihui.wgj.service.autotask;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fulihui.common.builder.rpc.RpcResultBuilder;
import com.fulihui.common.conv.BeanConv;
import com.fulihui.common.enums.SendLogStatusEnum;
import com.fulihui.common.enums.TemplateLogTypeEnum;
import com.fulihui.common.error.Errors;
import com.fulihui.common.error.InvokeServiceException;
import com.fulihui.common.result.rpc.BaseResult;
import com.fulihui.common.result.rpc.SimpleResult;
import com.fulihui.common.util.ConditionValidator;
import com.fulihui.common.util.DateUtils;
import com.fulihui.wgj.biz.AutoTaskBiz;
import com.fulihui.wgj.biz.WxUserInfoBiz;
import com.fulihui.wgj.config.properties.CommonProps;
import com.fulihui.wgj.dal.mybatis.domain.TemplateAutoLog;
import com.fulihui.wgj.dal.mybatis.domain.TemplateAutoTask;
import com.fulihui.wgj.dal.mybatis.repository.TemplateAutoLogRepository;
import com.fulihui.wgj.dal.mybatis.repository.TemplateAutoTaskRepository;
import com.fulihui.wgj.facade.dto.ClickNumStatisticDTO;
import com.fulihui.wgj.facade.dto.TemplateAutoLogDTO;
import com.fulihui.wgj.facade.dto.TemplateAutoTaskDTO;
import com.fulihui.wgj.facade.request.PrimaryKeyRequest;
import com.fulihui.wgj.facade.request.autotask.AutoLogPageQueryRequest;
import com.fulihui.wgj.facade.request.autotask.AutoLogQueryRequest;
import com.fulihui.wgj.facade.request.autotask.AutoLogUpdateRequest;
import com.fulihui.wgj.facade.request.autotask.AutoTaskQueryPageRequest;
import com.fulihui.wgj.facade.request.autotask.AutoTaskQueryRequest;
import com.fulihui.wgj.facade.request.autotask.AutoTaskSaveRequest;
import com.fulihui.wgj.facade.request.autotask.CalcAutoCountRequest;
import com.fulihui.wgj.facade.request.shortlink.ClickNumStatisticRequest;
import com.fulihui.wgj.facade.request.template.CalcSendCountRequest;
import com.fulihui.wgj.facade.result.autotask.TemplateAutoLogPageResult;
import com.fulihui.wgj.facade.result.autotask.TemplateAutoTaskPageResult;
import com.fulihui.wgj.facade.service.autotask.AutoTaskService;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;
import tk.mybatis.mapper.entity.Example;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 自动发送任务Service
 *
 * @author wang_wx
 * @date 2018-08-02
 */
@Component
@Service(interfaceClass = AutoTaskService.class, version = "1.0.0", timeout = 5000)
public class AutoTaskServiceImpl implements AutoTaskService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AutoTaskServiceImpl.class);

    @Autowired
    TemplateAutoTaskRepository templateAutoTaskRepository;

    @Autowired
    TemplateAutoLogRepository templateAutoLogRepository;

    @Autowired
    AutoTaskBiz autoTaskBiz;

    @Autowired
    WxUserInfoBiz wxUserInfoBiz;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    CommonProps commonProps;

    @Override
    public SimpleResult<Long> countUserAuto(CalcAutoCountRequest calcAutoCountRequest) throws InvokeServiceException {
        ConditionValidator.validate(calcAutoCountRequest);
        Integer logType = calcAutoCountRequest.getLogType();
        Date nowTime = new Date();
        // 当前时间的年月日
        String nowTimeDateStr = DateUtils.formatWebFormat(nowTime);
        // 今日的起始时间和结束时间
        String todayPrefixStr = nowTimeDateStr + DateUtils.BEGIN_OF_DAY;
        String todaySuffixStr = nowTimeDateStr + DateUtils.END_OF_DAY;
        Date todayPrefix;
        Date todaySuffix;
        try {
            todayPrefix = DateUtils.parseNewFormat(todayPrefixStr);
            todaySuffix = DateUtils.parseNewFormat(todaySuffixStr);
        } catch (ParseException e) {
            LOGGER.error("parseNewFormat error" + e);
            return RpcResultBuilder.failSimple(Errors.Commons.SYSTEM_ERROR);
        }
        // 自动化发送的条件
        CalcSendCountRequest calcSendCountRequest = autoTaskBiz.trance2CalcSendRequest(calcAutoCountRequest);
        Integer subscribeTimeStart = calcAutoCountRequest.getSubscribeTimeStart();
        Integer subscribeTimeEnd = calcAutoCountRequest.getSubscribeTimeEnd();
        Date subscribeTimeDateStart;
        Date subscribeTimeDateEnd;
        if (Objects.isNull(subscribeTimeEnd)) {
            // 第1种情况 关注时间仅： 前第几天 today：04-01  如前第2天 则是 03-30
            subscribeTimeDateStart = DateUtils.addDays(todayPrefix, -subscribeTimeStart);
            subscribeTimeDateEnd = DateUtils.addDays(todaySuffix, -subscribeTimeStart);
        } else {
            // 第2种情况 关注时间仅： 前第几天 至 前第几天 today：04-01  如前第4天 至 前第二天 则是 03-28至3-30
            subscribeTimeDateStart = DateUtils.addDays(todayPrefix, -subscribeTimeStart);
            subscribeTimeDateEnd = DateUtils.addDays(todaySuffix, -subscribeTimeEnd);
        }
        calcSendCountRequest.setSubStartTime(subscribeTimeDateStart);
        calcSendCountRequest.setSubEndTime(subscribeTimeDateEnd);
        //查询用户的数量
        Long recordCount = 0L;
        if (TemplateLogTypeEnum.SHOP.getValue() == logType.intValue()) {
            recordCount = wxUserInfoBiz.queryCount(calcSendCountRequest);
        } else if (TemplateLogTypeEnum.GAME.getValue() == logType.intValue()) {
            recordCount = wxUserInfoBiz.queryCount4Game(calcSendCountRequest);
        }
        return RpcResultBuilder.succSimple(recordCount);
    }

    @Override
    public BaseResult saveTask(AutoTaskSaveRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        CalcAutoCountRequest calcAutoCountRequest = request.getCalcAutoCountRequest();
        ConditionValidator.validate(calcAutoCountRequest);
        Long id = autoTaskBiz.saveTaskByRequest(request);
        LOGGER.info("saveTaskByRequest task id = {}", id);
        return Objects.nonNull(id) ? RpcResultBuilder.succ() : RpcResultBuilder.fail(Errors.Commons.SAVE_FAILED);
    }

    @Override
    public BaseResult updateTask(AutoTaskSaveRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        CalcAutoCountRequest calcAutoCountRequest = request.getCalcAutoCountRequest();
        ConditionValidator.validate(calcAutoCountRequest);
        Long id = request.getId();
        if (Objects.isNull(id)) {
            return RpcResultBuilder.fail(Errors.Commons.ID_CANNOT_BE_NULL);
        }
        Integer count = autoTaskBiz.updateTaskByRequest(request);
        LOGGER.info("updateTaskByRequest task id = {}", id);
        return count > 0 ? RpcResultBuilder.succ() : RpcResultBuilder.fail(Errors.Commons.UPDATE_FAILED);
    }

    @Override
    public TemplateAutoTaskPageResult pageQueryAutoTask(AutoTaskQueryPageRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        PageInfo<TemplateAutoTask> pageInfo = templateAutoTaskRepository.queryPageListByExample(buildQueryPageTask(request), request.getPage(), request.getRows());
        long total = pageInfo.getTotal();
        TemplateAutoTaskPageResult result = RpcResultBuilder.succPageResult(TemplateAutoTaskPageResult.class, pageInfo.getPageNum(), pageInfo.getPageSize(), Math.toIntExact(total));
        if (total > 0) {
            List<TemplateAutoTaskDTO> logDTOS = BeanConv.copy(pageInfo.getList(), TemplateAutoTaskDTO.class);
            result.setValue(logDTOS);
        }
        return result;
    }

    Example buildQueryPageTask(AutoTaskQueryPageRequest request) {
        Example example = new Example(TemplateAutoTask.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("appId", request.getAppId());
        if (StringUtils.isNotBlank(request.getTaskName())) {
            criteria.andLike("taskName", "%" + request.getTaskName() + "%");
        }
        if (Objects.nonNull(request.getLogType())) {
            criteria.andEqualTo("logType", request.getLogType());
        }
        if (Objects.nonNull(request.getStatus())) {
            criteria.andEqualTo("status", request.getStatus());
        }
        if (StringUtils.isNotBlank(request.getBeginDate())) {
            criteria.andGreaterThanOrEqualTo("gmtModified", request.getBeginDate());
        }
        if (StringUtils.isNotBlank(request.getEndDate())) {
            criteria.andLessThanOrEqualTo("gmtModified", request.getEndDate());
        }
        example.orderBy("gmtModified").asc();
        return example;
    }

    @Override
    public SimpleResult<List<TemplateAutoTaskDTO>> queryAutoTask(AutoTaskQueryRequest request) throws InvokeServiceException {
        List<TemplateAutoTask> templateAutoTasks = templateAutoTaskRepository.queryByExample(buildQueryTask(request));
        List<TemplateAutoTaskDTO> taskDTOS = null;
        if (!CollectionUtils.isEmpty(templateAutoTasks)) {
            taskDTOS = BeanConv.copy(templateAutoTasks, TemplateAutoTaskDTO.class);
        }
        return RpcResultBuilder.succSimple(taskDTOS);
    }

    Example buildQueryTask(AutoTaskQueryRequest request) {
        Example example = new Example(TemplateAutoTask.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("appId", request.getAppId());
        if (StringUtils.isNotBlank(request.getTaskName())) {
            criteria.andLike("taskName", "%" + request.getTaskName() + "%");
        }
        if (Objects.nonNull(request.getLogType())) {
            criteria.andEqualTo("logType", request.getLogType());
        }
        if (Objects.nonNull(request.getStatus())) {
            criteria.andEqualTo("status", request.getStatus());
        }
        if (StringUtils.isNotBlank(request.getBeginDate())) {
            criteria.andGreaterThanOrEqualTo("gmtModified", request.getBeginDate());
        }
        if (StringUtils.isNotBlank(request.getEndDate())) {
            criteria.andLessThanOrEqualTo("gmtModified", request.getEndDate());
        }
        example.orderBy("sendTime").asc();
        return example;
    }

    @Override
    public SimpleResult<List<TemplateAutoLogDTO>> queryAutoLog(AutoLogQueryRequest request) throws InvokeServiceException {
        List<TemplateAutoLog> templateAutoLogs = templateAutoLogRepository.queryByExample(buildExample4QueryLog(request));
        List<TemplateAutoLogDTO> autoLogDTOS = null;
        if (!CollectionUtils.isEmpty(templateAutoLogs)) {
            autoLogDTOS = BeanConv.copy(templateAutoLogs, TemplateAutoLogDTO.class);
        }
        return RpcResultBuilder.succSimple(autoLogDTOS);
    }

    @Override
    public TemplateAutoLogPageResult pageQueryAutoLog(AutoLogPageQueryRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        TemplateAutoLog templateAutoLogQuery = new TemplateAutoLog();
        templateAutoLogQuery.setTaskId(request.getTaskId());
        PageInfo<TemplateAutoLog> pageInfo = templateAutoLogRepository.queryPageListByWhere(templateAutoLogQuery, request.getPage(), request.getRows());
        long total = pageInfo.getTotal();
        TemplateAutoLogPageResult result = RpcResultBuilder.succPageResult(TemplateAutoLogPageResult.class, pageInfo.getPageNum(), pageInfo.getPageSize(), Math.toIntExact(total));
        if (total > 0L) {
            List<TemplateAutoLogDTO> logDTOS = BeanConv.copy(pageInfo.getList(), TemplateAutoLogDTO.class);
            if (!CollectionUtils.isEmpty(logDTOS)) {
                logDTOS.stream().forEach(logDTO -> {
                    try {
                        // 设置默认0
                        logDTO.setClickNum("--");
                        ClickNumStatisticRequest clickNumStatisticRequest = new ClickNumStatisticRequest();
                        ArrayList<String> urls = Lists.newArrayList();
                        Date startTime = logDTO.getSendStartTime();
                        Date endTime = new Date();
                        String jumpUrl = logDTO.getJumpUrl();
                        // 跳转链接不为空并且必须为短链的
                        String[] shortLinkHostList = commonProps.getShortLinkHostList();
                        if (StringUtils.isNotBlank(jumpUrl) && null != shortLinkHostList && shortLinkHostList.length > 0) {
                            List<String> strings = Arrays.asList(shortLinkHostList);
                            boolean containsUrl = false;
                            for (String string : strings) {
                                boolean contains = StringUtils.contains(jumpUrl, string);
                                if (contains) {
                                    containsUrl = true;
                                    break;
                                }
                            }
                            if (containsUrl) {
                                urls.add(jumpUrl);
                                clickNumStatisticRequest.setBeginTime(startTime);
                                clickNumStatisticRequest.setEndTime(endTime);
                                clickNumStatisticRequest.setUrls(urls);
                                String response = restTemplate.postForObject(commonProps.getShortLinkHost() + "/api/queryClickNumStatistic", clickNumStatisticRequest, String.class);
                                LOGGER.info("调用短链接进行查询点击数响应：response={}", response);
                                if (StringUtils.isNotBlank(response)) {
                                    JSONObject parseObject = JSONObject.parseObject(response);
                                    if ("00".equals(parseObject.get("code"))) {
                                        List<ClickNumStatisticDTO> dtoList = parseObject.getJSONArray("result").toJavaList(ClickNumStatisticDTO.class);
                                        if (!CollectionUtils.isEmpty(dtoList)) {
                                            ClickNumStatisticDTO statisticDTO = dtoList.get(0);
                                            Long clickNum = statisticDTO.getClickNum();
                                            logDTO.setClickNum(String.valueOf(clickNum));
                                        }
                                    }
                                }
                            }
                        }
                    } catch (Exception e) {
                        LOGGER.error("模板记录点击数调用短链系统发生错误", e);
                        return;
                    }
                });
            }
            result.setValue(logDTOS);
        }
        LOGGER.info("templateAutoLogPageResult = {}", result);
        return result;
    }

    @Override
    public BaseResult updateAutoLogAccumulate(AutoLogUpdateRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        TemplateAutoLog exist = templateAutoLogRepository.queryById(request.getId());
        if (Objects.isNull(exist)) {
            return RpcResultBuilder.fail(Errors.Commons.RECORD_NOT_EXISTS);
        }
        TemplateAutoLog templateAutoLog = new TemplateAutoLog();
        templateAutoLog.setId(request.getId());
        templateAutoLog.setGmtModified(new Date());
        templateAutoLog.setStatus(request.getSendStatus());
        templateAutoLog.setSendSuccessCount(request.getSendSuccessCount());
        templateAutoLog.setSendFailCount(request.getSendFailCount());
        templateAutoLog.setSendStartTime(request.getSendStartTime());
        templateAutoLog.setSendEndTime(request.getSendEndTime());
        Integer count = templateAutoLogRepository.updateAccumulate(templateAutoLog);
        return count > 0 ? RpcResultBuilder.succ() : RpcResultBuilder.fail(Errors.Commons.UPDATE_FAILED);
    }

    Example buildExample4QueryLog(AutoLogQueryRequest request) {
        Example example = new Example(TemplateAutoLog.class);
        Example.Criteria criteria = example.createCriteria();
        if (Objects.nonNull(request.getId())) {
            criteria.andEqualTo("id", request.getId());
        }
        if (Objects.nonNull(request.getTaskId())) {
            criteria.andEqualTo("taskId", request.getTaskId());
        }
        example.orderBy("gmtModified").desc();
        return example;
    }

    @Override
    public BaseResult sendTask(PrimaryKeyRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);

        Object taskId = request.getId();
        Date nowTime = new Date();
        // 当前时间的年月日
        String nowTimeDateStr = DateUtils.formatWebFormat(nowTime);
        // 今日的起始时间和结束时间
        String todayPrefixStr = nowTimeDateStr + DateUtils.BEGIN_OF_DAY;
        String todaySuffixStr = nowTimeDateStr + DateUtils.END_OF_DAY;
        Date todayPrefix;
        Date todaySuffix;
        try {
            todayPrefix = DateUtils.parseNewFormat(todayPrefixStr);
            todaySuffix = DateUtils.parseNewFormat(todaySuffixStr);
        } catch (ParseException e) {
            LOGGER.error("parseNewFormat error" + e);
            return RpcResultBuilder.failSimple(Errors.Commons.SYSTEM_ERROR);
        }

        TemplateAutoTask templateAutoTask = templateAutoTaskRepository.queryById(taskId);
        // 业务类型
        Integer logType = templateAutoTask.getLogType();
        String sendCondition = templateAutoTask.getSendCondition();
        // 自动化发送的条件
        CalcAutoCountRequest calcAutoCountRequest = JSON.parseObject(sendCondition, CalcAutoCountRequest.class);
        CalcSendCountRequest calcSendCountRequest = autoTaskBiz.trance2CalcSendRequest(calcAutoCountRequest);
        Integer subscribeTimeStart = calcAutoCountRequest.getSubscribeTimeStart();
        Integer subscribeTimeEnd = calcAutoCountRequest.getSubscribeTimeEnd();
        Date subscribeTimeDateStart;
        Date subscribeTimeDateEnd;
        if (Objects.isNull(subscribeTimeEnd)) {
            // 第1种情况 关注时间仅： 前第几天 today：04-01  如前第2天 则是 03-30
            subscribeTimeDateStart = DateUtils.addDays(todayPrefix, -subscribeTimeStart);
            subscribeTimeDateEnd = DateUtils.addDays(todaySuffix, -subscribeTimeStart);
        } else {
            // 第2种情况 关注时间仅： 前第几天 至 前第几天 today：04-01  如前第4天 至 前第二天 则是 03-28至3-30
            subscribeTimeDateStart = DateUtils.addDays(todayPrefix, -subscribeTimeStart);
            subscribeTimeDateEnd = DateUtils.addDays(todaySuffix, -subscribeTimeEnd);
        }
        calcSendCountRequest.setSubStartTime(subscribeTimeDateStart);
        calcSendCountRequest.setSubEndTime(subscribeTimeDateEnd);
        //查询用户的数量
        Long recordCount = 0L;
        if (TemplateLogTypeEnum.SHOP.getValue() == logType.intValue()) {
            recordCount = wxUserInfoBiz.queryCount(calcSendCountRequest);
        } else if (TemplateLogTypeEnum.GAME.getValue() == logType.intValue()) {
            recordCount = wxUserInfoBiz.queryCount4Game(calcSendCountRequest);
        }
        TemplateAutoLog templateAutoLog = new TemplateAutoLog();
        templateAutoLog.setTaskId((Long) taskId);
        templateAutoLog.setSendCount(recordCount);
        templateAutoLog.setSendSuccessCount(0L);
        templateAutoLog.setSendFailCount(0L);
        templateAutoLog.setSendStartTime(new Date());
        templateAutoLog.setSendEndTime(new Date());
        templateAutoLog.setTemplateId(templateAutoTask.getTemplateId());
        templateAutoLog.setTemplateContent(templateAutoTask.getTemplateContent());
        templateAutoLog.setTemplateData(templateAutoTask.getTemplateData());
        templateAutoLog.setJumpUrl(templateAutoTask.getJumpUrl());
        templateAutoLog.setMiniApp(templateAutoTask.getMiniApp());
        templateAutoLog.setMiniAppId(templateAutoTask.getMiniAppId());
        templateAutoLog.setMiniProgramUrl(templateAutoTask.getMiniProgramUrl());
        templateAutoLog.setSendConditionDesc(templateAutoTask.getSendConditionDesc());
        templateAutoLog.setSendCondition(templateAutoTask.getSendCondition());
        if (recordCount == 0L) {
            // 发送计算数量是0 直接插入一条发送完成的记录
            templateAutoLog.setStatus(SendLogStatusEnum.complete.getCode());
            templateAutoLogRepository.saveSelective(templateAutoLog);
        } else {
            templateAutoLog.setStatus(SendLogStatusEnum.pushing.getCode());
            templateAutoLogRepository.saveSelective(templateAutoLog);
            autoTaskBiz.sendAutoMsg(calcSendCountRequest, templateAutoTask, templateAutoLog);
        }
        return RpcResultBuilder.succ();
    }

    @Override
    public SimpleResult<TemplateAutoTaskDTO> queryAutoTaskById(PrimaryKeyRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        TemplateAutoTask templateAutoTask = templateAutoTaskRepository.queryById(request.getId());
        TemplateAutoTaskDTO autoTaskDTO = null;
        if (Objects.nonNull(templateAutoTask)) {
            autoTaskDTO = BeanConv.copy(templateAutoTask, TemplateAutoTaskDTO.class);
        }
        return RpcResultBuilder.succSimple(autoTaskDTO);
    }
}
